package engine;

import static org.lwjgl.opengl.GL11.*; 

import java.io.Serializable;

import org.lwjgl.LWJGLException;
import org.lwjgl.opengl.Display;
import org.lwjgl.opengl.DisplayMode;

import engine.exceptions.EExceptionCause;
import engine.exceptions.ExceptionHandler;
import engine.exceptions.MADException;
import engine.game.Game;
import engine.graphics.IRender;
import engine.input.IInput;
import engine.system.IExit;
import engine.system.IInit;
import engine.system.MADFrameRate;
import engine.system.MADSystem;


public class Engine implements IInit, IExit, IInput, IRender, Serializable{

	private static final long serialVersionUID = 1L;
	
//	public static final int WIDTH = (int) MADSystem.getScreenSize().getWidth() / 2;
//	public static final int HEIGHT = (int) MADSystem.getScreenSize().getHeight() / 2; 
//	public static final int WIDTH = (int) MADSystem.getScreenSize().getWidth();
//	public static final int HEIGHT = (int) MADSystem.getScreenSize().getHeight() ; 
	public static final int WIDTH = 800, HEIGHT = 600 ; 
	public static final int LEFT = (int) MADSystem.centerToScreen(WIDTH, HEIGHT).getWidth(); 
	public static final int TOP = (int) MADSystem.centerToScreen(WIDTH, HEIGHT).getHeight();

	public static String APP_TITLE = "MADEngine - Pre Alpha";
	
	private Game game ; 
	
	public Engine(){
		try{
			init(); 
		}catch(Exception e){
			ExceptionHandler.displayException(new MADException(EExceptionCause.E_CONSTRUCT_ENGINE, e));
		}
	}

	public void startGameLoop(){
		try{
			gameLoop();
		}catch(Exception e){
			ExceptionHandler.displayException(new MADException(EExceptionCause.E_ENGINE_START_GAMELOOP, e));
		}
	}
	
	public boolean gameInitialised(){
		return game != null ; 
	}

	public void addNewGameInstance(Game g){
		if(this.gameInitialised()){
			ExceptionHandler.displayException(new MADException(EExceptionCause.E_ENGINE_GAME_INSTANCE_EXISTS, null)); 
			return ; 
		}
		if(g == null){
			ExceptionHandler.displayException(new MADException(EExceptionCause.E_ENGINE_GAME_INSTANCE_INVALID, null));
			return ; 
		}
		this.game = g;
		APP_TITLE = game.getName(); 
	}
	
	@Override
	public void init() {
		try{
			initComponents(); 
			initAL(); 
			initGL(); 
		}catch(Exception e){
			ExceptionHandler.displayException(new MADException(EExceptionCause.E_ENGINE_INIT, e)); 
		}
	}
	
	private void initComponents() {
		try {
			Display.setDisplayMode(new DisplayMode(WIDTH, HEIGHT));
			Display.setFullscreen(true);
			Display.setLocation(LEFT, TOP); 
			Display.setTitle(APP_TITLE); 
			Display.create(); 			
		} catch (LWJGLException e) {
			ExceptionHandler.displayException(new MADException(EExceptionCause.E_ENGINE_INIT_COMPS, e));
		} 
	}

	private void initGL() {
		try{
			MADGL.init(); 
			MADFrameRate.start(); 
		}catch(Exception e){
			ExceptionHandler.displayException(new MADException(EExceptionCause.E_ENGINE_GL_INIT, e)); 
		}
	}

	private void initAL(){
		try{
			MADAL.init();
		}catch(Exception e){
			ExceptionHandler.displayException(new MADException(EExceptionCause.E_ENGINE_AL_INIT, e)); 
		}
	}
	
	private void gameLoop() {
		while(!Display.isCloseRequested()){
			try{
				getInput();
				update();
				render();
				syncDisplay();
			}catch(Exception e){
				ExceptionHandler.displayException(new MADException(EExceptionCause.E_ENGINE_GAMELOOP, e)); 
			}
		}
	}
	
	private void syncDisplay() {
		try{
			Display.update();
			Display.sync(MADFrameRate.SYNC_FRAME_RATE); 
		}catch(Exception e){
			ExceptionHandler.displayException(new MADException(EExceptionCause.E_ENGINE_SYNC_DISPLAY, e)); 
		}
	}

	@Override
	public void exit() {
		try{
			MADAL.exit(); 
			Display.destroy(); 
			System.exit(0); 
		}catch(Exception e){
			ExceptionHandler.displayException(new MADException(EExceptionCause.E_ENGINE_EXIT, e));
			System.exit(1);
		}
	}
	
	@Override
	public void update() {
		try{
			MADFrameRate.update(); 
			if(this.gameInitialised())
				game.update(); 
		}catch(Exception e){
			ExceptionHandler.displayException(new MADException(EExceptionCause.E_ENGINE_UPDATE, e)); 
		}
	}

	@Override
	public void render() {
		try{
			glClear(GL_COLOR_BUFFER_BIT); 
			if(this.gameInitialised())
				game.render(); 
		}catch(Exception e){
			ExceptionHandler.displayException(new MADException(EExceptionCause.E_ENGINE_RENDER, e)); 
		}
	}

	@Override
	public void getInput() {
		try{
			if(this.gameInitialised())
				game.getInput(); 
		}catch(Exception e){
			ExceptionHandler.displayException(new MADException(EExceptionCause.E_ENGINE_INPUT, e));
		}
	}


	
}
